/***************************************************
 * Author:		Xycaleth
 * Description:	Handles weapons fire events.
 * Revision:	$Id$
 **************************************************/

#include "../game/g_local.h"

#define	ARROW_MAX_VELOCITY	2200		// A quite fast speed.
#define ARROW_MAX_DAMAGE	100
#define ARROW_LIFETIME		1000 * 60 * 5	// 5 minutes to live

vec3_t forward, right, up, muzzle;

// ===============================================
// S_ArrowStick - If arrow gets stuck in something
// ===============================================
void S_ArrowStick ( gentity_t * ent, trace_t * tr )
{
	vec3_t	dir, normal;

	BG_EvaluateTrajectoryDelta (&ent->s.pos, level.time, dir);
	if ( tr->entityNum < 0 || tr->entityNum >= MAX_CLIENTS )
	{
		// DotProduct
		// -1 or 1 = right angles to normal
		// 0 = parallel to normal
		float	dot;

		VectorCopy (tr->plane.normal, normal);

		VectorNormalize (dir);
		VectorNormalize (normal);

		dot = DotProduct (dir, normal);
		if ( dot > -0.3f )
		{
			// Too much of right angle to normal
			ent->s.eFlags &= ~EF_MISSILE_STICK;
			ent->flags |= FL_BOUNCE_SHRAPNEL;
			ent->bounceCount = 10;
			return;
		}
	}
	else
	{
		// Carnage!
		G_Damage (&g_entities[tr->entityNum], &g_entities[ent->s.owner], &g_entities[ent->s.owner], dir, tr->endpos, ent->damage, 0, MOD_BOWCASTER);
	}
	
	G_SetOrigin (ent, tr->endpos);
	VectorCopy (dir, ent->s.pos.trDelta);

	ent->think = G_FreeEntity;
	ent->nextthink = level.time + ARROW_LIFETIME;
}

// ========================================
// S_WP_FireBow - Called upon firing bow
// ========================================
void S_WP_FireBow ( gentity_t * ent )
{
	gentity_t	* arrow;
	float		velocity;

	velocity = ((float)(level.time - ent->client->ps.weaponChargeTime) / (float)weaponData[WP_LONGBOW].maxCharge) * (float)ARROW_MAX_VELOCITY;
	velocity = velocity > ARROW_MAX_VELOCITY ? ARROW_MAX_VELOCITY : velocity;

	arrow = CreateMissile (muzzle, forward, velocity, 10000, ent, qfalse);
	arrow->classname = "arrow_proj";
	arrow->s.weapon = WP_LONGBOW;
	arrow->s.eFlags |= EF_MISSILE_STICK;

	VectorSet (arrow->r.maxs, 10, 2, 2);
	VectorScale (arrow->r.maxs, -1, arrow->r.mins);

	arrow->s.pos.trType = TR_GRAVITY;

	arrow->damage = ARROW_MAX_DAMAGE * (velocity / ARROW_MAX_VELOCITY);
	arrow->methodOfDeath = MOD_BLASTER;
	arrow->clipmask = MASK_SHOT;
}

//======================================
// WP_FireMelee
//======================================
const int MELEE_RANGE = 8;
const int MELEE_DAMAGE = 12;
void WP_FireMelee ( gentity_t* ent )
{
	trace_t trace;
	vec3_t punchMuzzle;
	vec3_t mins, maxs, end;
	
	VectorCopy (ent->client->ps.origin, punchMuzzle);
	punchMuzzle[2] += ent->client->ps.viewheight - 6;
	
	VectorMA (punchMuzzle, 20.0f, forward, punchMuzzle);
	VectorMA (punchMuzzle, 4.0f, right, punchMuzzle);
	
	VectorMA (punchMuzzle, MELEE_RANGE, forward, end);
	
	VectorSet (maxs, 6.0f, 6.0f, 6.0f);
	VectorNegate (maxs, mins);
	
	trap_Trace (&trace, punchMuzzle, mins, maxs, end, ent->s.number, MASK_SHOT);
	
	if ( trace.entityNum != ENTITYNUM_NONE )
	{
		gentity_t* hitPlayer = &g_entities[trace.entityNum];
		
		G_Sound (ent, CHAN_AUTO, G_SoundIndex (va ("sound/weapons/melee/punch%d", Q_irand (1, 4))));
		
		if ( !hitPlayer->client || !hitPlayer->takedamage )
		{
			return;
		}
		
		G_Damage (hitPlayer, ent, ent, forward, trace.endpos, MELEE_DAMAGE, DAMAGE_NO_ARMOR, MOD_MELEE);
	}
}

//======================================
// S_FireWeapon
// Redirects calls to relevant functions.
//======================================
extern void FireVehicleWeapon( gentity_t *ent, qboolean alt_fire );
void S_FireWeapon ( gentity_t * ent, qboolean altFire )
{
	if ( ent && ent->client && ent->inuse && ent->client->NPC_class == CLASS_VEHICLE )
	{
		FireVehicleWeapon (ent, altFire);
		return;
	}
	
	AngleVectors (ent->client->ps.viewangles, forward, right, up);
	CalcMuzzlePoint (ent, forward, right, up, muzzle);

	switch ( ent->client->ps.weapon )
	{
		case WP_MELEE:
			WP_FireMelee (ent);
		break;

		case WP_LONGBOW:
		case WP_SHORTBOW:
			if ( !altFire )
			{
				S_WP_FireBow (ent);
			}
		break;
		
		// All melee weapons are handled in bg_saber.c.

		default:
			G_Printf ("%s " S_COLOR_WHITE "fired unknown weapon %d!\n", ent->client->pers.netname, ent->client->ps.weapon);
		break;
	}
}

// eof
